#include <stdlib.h>
#include <stdio.h>
#include "list.h"

typedef struct {
        struct list_head hook;
        int lsn;
} buf_t;

typedef struct {
        struct list_head used_list;
        struct list_head wait_list;
        int last_lsn;
} buf_manager_t;

void buf_manager_init(buf_manager_t *manager) {
        manager->last_lsn = 0;
        INIT_LIST_HEAD(&manager->used_list);
        INIT_LIST_HEAD(&manager->wait_list);
}

void buf_manager_destroy(buf_manager_t *manager) {
        struct list_head *pos, *n;
        list_for_each_safe(pos, n, &manager->used_list) {
                list_del_init(pos);
                free((void *)pos);
        }

        list_for_each_safe(pos, n, &manager->wait_list) {
                list_del_init(pos);
                free((void *)pos);
        }
}

void buf_manager_extend(buf_manager_t *manager) {
        buf_t *b = malloc(sizeof(buf_t));
        b->lsn = ++manager->last_lsn;
        list_add_tail(&b->hook, &manager->used_list);
}

/** wait -> used
 */
void buf_manager_swapin(buf_manager_t *manager) {
        if (!list_empty_careful(&manager->wait_list)) {
                struct list_head *first = manager->wait_list.next;
                list_del(first);
                list_add_tail(first, &manager->used_list);
        }
}

/** used -> wait
 */
void buf_manager_swapout(buf_manager_t *manager) {
        if (!list_empty_careful(&manager->used_list)) {
                struct list_head *first = manager->used_list.next;
                list_del(first);
                list_add_tail(first, &manager->wait_list);
        } else {
                buf_manager_extend(manager);

        }
}

void buf_manager_print(buf_manager_t *manager) {
        struct list_head *pos;
        buf_t *buf;

        list_for_each(pos, &manager->used_list) {
                buf = (buf_t *)pos;
                printf("used %d\n", buf->lsn);
        }

        list_for_each(pos, &manager->wait_list) {
                buf = (buf_t *)pos;
                printf("wait %d\n", buf->lsn);
        }
}

int main(int argc, char *argv[]) {
        buf_manager_t manager;

        buf_manager_init(&manager);

        buf_manager_extend(&manager);
        buf_manager_extend(&manager);

        buf_manager_swapout(&manager);
        buf_manager_swapout(&manager);
        buf_manager_swapout(&manager);

        buf_manager_swapin(&manager);

        buf_manager_print(&manager);

        buf_manager_destroy(&manager);

        return 0;
}
